<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
 * Класс для валидирования форм
 * Расширяет соответствующий стандартный класс
 * 
 * @package CoreFramework
 * @version 1.0
 * @author Gennadiy Kozlenko
 */
class CF_Validation extends CI_Validation {

   /**
    * Запуск валидатора
    * Эта функция делает всю работу
    *
    * @access public
    * @return boolean
    */      
   function run() {
      // Do we even have any data to process?  Mm?
      if (count($_POST) == 0 OR count($this->_rules) == 0)
      {
         return FALSE;
      }
   
      // Load the language file containing error messages
      $this->CI->lang->load('validation');
                     
      // Cycle through the rules and test for errors
      foreach ($this->_rules as $field => $rules)
      {
         //Explode out the rules!
         $ex = explode('|', $rules);

         // Is the field required?  If not, if the field is blank  we'll move on to the next test
         if ( ! in_array('required', $ex, TRUE) AND strpos($rules, 'callback_') === FALSE)
         {
            if ( ! isset($_POST[$field]) OR $_POST[$field] == '')
            {
               continue;
            }
         }
         
         /*
          * Are we dealing with an "isset" rule?
          *
          * Before going further, we'll see if one of the rules
          * is to check whether the item is set (typically this
          * applies only to checkboxes).  If so, we'll
          * test for it here since there's not reason to go
          * further
          */
         if ( ! isset($_POST[$field]))
         {         
            if (in_array('isset', $ex, TRUE) OR in_array('required', $ex))
            {
               if ( ! isset($this->_error_messages['isset']))
               {
                  if (FALSE === ($line = $this->CI->lang->line('isset')))
                  {
                     $line = 'The field was not set';
                  }                     
               }
               else
               {
                  $line = $this->_error_messages['isset'];
               }
               // Получаем название поля
               $mfield = $field;
               if (isset($this->_fields[$field])) {
                  $mfield = $this->_fields[$field];
               } elseif (false !== $this->CI->lang->line($field . '_field')) {
                  $mfield = $this->CI->lang->line($field . '_field');
               }
               // Получаем сообщение об ошибке
               $message = sprintf($line, $mfield);
               // Вносим ошибку в стек ошибок
               $this->CI->errors->set($field, $message);
               $this->_error_array[] = $message;
            }
                  
            continue;
         }
   
         /*
          * Set the current field
          *
          * The various prepping functions need to know the
          * current field name so they can do this:
          *
          * $_POST[$this->_current_field] == 'bla bla';
          */
         $this->_current_field = $field;

         // Cycle through the rules!
         foreach ($ex As $rule)
         {
            // Is the rule a callback?         
            $callback = FALSE;
            if (substr($rule, 0, 9) == 'callback_')
            {
               $rule = substr($rule, 9);
               $callback = TRUE;
            }
            
            // Strip the parameter (if exists) from the rule
            // Rules can contain a parameter: max_length[5]
            $param = FALSE;
            if (preg_match("/(.*?)\[(.*?)\]/", $rule, $match))
            {
               $rule   = $match[1];
               $param   = $match[2];
            }
            
            // Call the function that corresponds to the rule
            if ($callback === TRUE)
            {
               if ( ! method_exists($this->CI, $rule))
               {       
                  continue;
               }
               
               $result = $this->CI->$rule($_POST[$field], $param);
               $this->$field = $_POST[$field];   
               
               // If the field isn't required and we just processed a callback we'll move on...
               if ( ! in_array('required', $ex, TRUE) AND $result !== FALSE)
               {
                  continue 2;
               }
               
            }
            else
            {            
               if ( ! method_exists($this, $rule))
               {
                  /*
                   * Run the native PHP function if called for
                   *
                   * If our own wrapper function doesn't exist we see
                   * if a native PHP function does. Users can use
                   * any native PHP function call that has one param.
                   */
                  if (function_exists($rule))
                  {
                     $_POST[$field] = $rule($_POST[$field]);
                     $this->$field = $_POST[$field];
                  }
                                 
                  continue;
               }
               
               $result = $this->$rule($_POST[$field], $param);
               $this->$field = $_POST[$field];
            }
                        
            // Did the rule test negatively?  If so, grab the error.
            if ($result === FALSE)
            {
               if ( ! isset($this->_error_messages[$rule]))
               {
                  if (FALSE === ($line = $this->CI->lang->line($rule)))
                  {
                     $line = 'Unable to access an error message corresponding to your field name.';
                  }                  
               }
               else
               {
                  $line = $this->_error_messages[$rule];;
               }            

               // Получаем название поля
               $mfield = $field;
               if (isset($this->_fields[$field])) {
                  $mfield = $this->_fields[$field];
               } elseif (false !== $this->CI->lang->line($field . '_field')) {
                  $mfield = $this->CI->lang->line($field . '_field');
               }
               $mparam = ( ! isset($this->_fields[$param])) ? $param : $this->_fields[$param];
               $message = sprintf($line, $mfield, $mparam);
               // Вносим ошибку в стек ошибок
               $this->CI->errors->set($field, $message);
               
               // Set the error variable.  Example: $this->username_error
               $error = $field.'_error';
               $this->$error = $this->_error_prefix.$message.$this->_error_suffix;

               // Add the error to the error array
               $this->_error_array[] = $message;            
               continue 2;
            }            
         }
         
      }
      
      $total_errors = count($this->_error_array);

      /*
       * Recompile the class variables
       *
       * If any prepping functions were called the $_POST data
       * might now be different then the corresponding class
       * variables so we'll set them anew.
       */   
      if ($total_errors > 0)
      {
         $this->_safe_form_data = TRUE;
      }
      
      $this->set_fields();

      // Did we end up with any errors?
      if ($total_errors == 0)
      {
         return TRUE;
      }
      
      // Generate the error string
      foreach ($this->_error_array as $val)
      {
         $this->error_string .= $this->_error_prefix.$val.$this->_error_suffix."\n";
      }

      return FALSE;
   }
   
   /**
    * Валидирование url
    *
    * @access public
    * @param string $str
    * @return boolean
    */
   function valid_url($str) {
      return (!preg_match('~^(http|https)://[a-z0-9]+([-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?/.*)?$~i', $str)) ? false : true;
   } // end valid_url
   
   /**
    * Валидирование на минимальную границу значения
    *
    * @access public
    * @param string $str
    * @param string $val
    * @return boolean
    */
   function min_value($str, $val) {
      return $str >= $val;
   } // end min_value
   
   /**
    * Валидирование на максимальную границу значения
    *
    * @access public
    * @param string $str
    * @param string $val
    * @return boolean
    */
   function max_value($str, $val) {
      return $str <= $val;
   } // end max_value
   
   /**
    * Minimum Length
    *
    * @access  public
    * @param   string
    * @return  bool
    */   
   function min_length($str, $val) {
      if (preg_match("/[^0-9]/", $val)) {
         return FALSE;
      }
      return (mb_strlen($str, $this->CI->config->item('charset')) < $val) ? FALSE : TRUE;
   }
   
   /**
    * Max Length
    *
    * @access  public
    * @param   string
    * @return  bool
    */   
   function max_length($str, $val) {
      if (preg_match("/[^0-9]/", $val)) {
         return FALSE;
      }
      return (mb_strlen($str, $this->CI->config->item('charset')) > $val) ? FALSE : TRUE;
   }
   
   /**
    * Exact Length
    *
    * @access  public
    * @param   string
    * @return  bool
    */   
   function exact_length($str, $val) {
      if (preg_match("/[^0-9]/", $val)) {
         return FALSE;
      }
      return (mb_strlen($str, $this->CI->config->item('charset')) != $val) ? FALSE : TRUE;
   }
   
}
